<?php
declare (strict_types=1);

namespace app\common\tool\WeChat;

use app\common\model\Order;
use app\common\model\User;
use app\common\model\VillageProduct;
use app\common\tool\WeChat\Exception\WeChatException;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\RequestOptions;
use think\facade\Log;
use WeChat\Exceptions\InvalidResponseException;
use WeChat\Exceptions\LocalCacheException;
use WeChat\Oauth;

class WeChat
{

    /**
     * @var mixed 微信配置参数
     */
    protected $config;

    public function __construct()
    {
        $this->config = config('pay')['wechat'];
    }

    /**
     * @param $redirect_url
     * @param $state
     * @param $scope - 授权类类型(可选值snsapi_base - 获取openid用|snsapi_userinfo - 获取微信用户信息用)
     * @return string
     * @throws WeChatException
     * 原点 2022年12月8日15:38:24 微信公众号授权跳转接口
     */
    public function getOauthRedirect($redirect_url, $state = '', $scope = 'snsapi_base')
    {
        try {
            return Oauth::instance($this->config)->getOauthRedirect($redirect_url, $state, $scope);
        } catch (\Exception $e) {
            throw new WeChatException('加载失败：' . $e->getMessage(), -1);
        }
    }


    /**
     * @param $code
     * @return array
     * @throws WeChatException
     * 原点 2022年12月8日15:40:15 获取openid,静默授权(需getOauthRedirect方法scope需为 snsapi_base)
     */
    public function getOauthAccessToken($code)
    {
        try {
            return Oauth::instance($this->config)->getOauthAccessToken($code);
        } catch (\Exception $e) {
            throw new WeChatException('加载失败：' . $e->getMessage(), -1);
        }
    }

    /**
     * @param $access_token
     * @param $openid
     * @param $lang
     * @return array
     * @throws WeChatException
     * 原点 2022年12月8日15:43:21 拉取用户信息(需getOauthRedirect方法scope需为 snsapi_userinfo)
     */
    public function getUserInfo($access_token, $openid, $lang = 'zh_CN')
    {
        try {
            return Oauth::instance($this->config)->getUserInfo($access_token, $openid, $lang);
        } catch (\Exception $e) {
            throw new WeChatException('获取失败：' . $e->getMessage(), -1);
        }
    }

    /**
     * 生成商品太阳码
     * @param $pid
     * @param string $linkurl
     * @param string $scene
     * @return array
     */
    public function generateProductQrcode($pid, $linkurl='pages/index/index',$scene=""): array
    {
        $path = "uploads/qrcode/";

        if(!is_dir($path)) @mkdir($path,0777,true);
        $filename = $path.time()."_pid_{$pid}.png";

        $access_token = $this->getAccessToken();

        $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=$access_token";

        $data = [
            "scene" => "pid,{$pid}",//'user,' . $posts['uid']
            "is_hyaline" => true, //透明底色
            "page" => $linkurl,//$posts['linkurl']
        ];
        $result = $this->httpPost($url, $data);  //调用接口 生成二维码数据流

        $err = json_decode($result,true);

        if(isset($err['errcode'])){
            Log::write("generateQrcode:result:uid[$pid]".$result);
            return ['code'=>-1,'msg'=>'操作失败'];
        }

        file_put_contents($filename, $result); // 数据写入图片 生成用户二维码

        VillageProduct::update(['qrcode'=>'/'.$filename],['id'=>$pid]);

        return ['code'=>1,'msg'=>'success','data'=>'/'.$filename];
    }

    /**
     * 生成订单核销码（小程序）
     * @param $uid
     * @param string $linkurl
     * @param string $scene
     * @return array
     */
    public function generateScanCode($code, $linkurl='pages/index/index',$scene=""): array
    {
        $path = "uploads/scan/";

        if(!is_dir($path)) @mkdir($path,0777,true);
        $filename = $path.time()."_{$code}.png";

        $access_token = $this->getAccessToken();
        $url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=$access_token";

        $data = [
            "scene" => "code,{$code}",
            "is_hyaline" => true, //透明底色
            "page" => $linkurl,//$posts['linkurl']
        ];
        $result = $this->httpPost($url, $data);  //调用接口 生成二维码数据流

        $err = json_decode($result,true);

        if(isset($err['errcode'])){
            Log::write("generateScanCode:result:code[$code]".$result);
            return ['code'=>-1,'msg'=>'操作失败'];
        }

        file_put_contents($filename, $result); // 数据写入图片 生成用户二维码

        Order::update(['scan_code'=>$filename],['write_off_code'=>$code]);

        return ['code'=>1,'msg'=>'success','data'=>$filename];
    }

    /**
     * 敏感词过滤
     * @param $msg
     * @return mixed
     */
    public function msgSecCheck($msg)
    {
        $data = json_encode(array('content' => $msg), JSON_UNESCAPED_UNICODE);//(gcd 鞚吥組呮)
        $access_token = $this->getAccessToken();
        $url = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token=$access_token";
        $info = $this->http_request($url, $data);

        return json_decode($info, true);
    }

    private function http_request($url, $data = null)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        if (!empty($data)) {
            curl_setopt($curl, CURLOPT_POST, TRUE);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }

    public function httpPost($url, $data): string
    {
        $client = new Client();
        $options = [
            RequestOptions::HEADERS => ['Content-Type'=>'application/json; charset=utf-8'],
            RequestOptions::JSON => $data
        ];

        try {
            return $client->post($url, $options)->getBody()->getContents();
        } catch (GuzzleException $e) {
            return $e->getMessage();
        }
    }

    private function getAccessToken(): string
    {
        $config = config('pay')['wechat'];
        try {
            return (new \WeChat\Contracts\BasicWeChat($config))->getAccessToken();
        } catch (InvalidResponseException | LocalCacheException $e) {
            return '';
        }
    }

    /**
     * 设置配置信息
     * @param array $config 配置内容
     * @return $this
     */
    public function withConfig(array $config): self
    {
        $this->config = $config;
        return $this;
    }

}